package com.xiaotu.common.util;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;

import net.sf.json.JSONObject;
import us.codecraft.webmagic.Page;

/**
 * @类名 TVProcessUtils
 * @日期 2017年2月14日
 * @作者 高海军
 * @功能 爬取的作品页面数据的处理帮助类
 */
public class TVProcessUtils
{
    private static final Logger LOGGER = LoggerFactory
            .getLogger(TVProcessUtils.class);

    public static final String PAGE_TVNAME = "pageTVName";

    public static final String PAGE_UPDATE_SET = "pageUpdateSet";

    private static final List<String> TV_MOV_TYPE_LIST = Arrays.asList("1", "2",
            "3", "4", "6");

    /**
     * @param targetTvMap   爬取的目标作品
     * @param pageTvName    页面中作品名称后
     * @param pageTvType    页面中作品类型
     * @param pageActors    页面中作品主要演员，多个用SepratorUtil.SEP_COMMA_EN分割
     * @param pageDirectors 页面中作品导演，多个用SepratorUtil.SEP_COMMA_EN分割
     * @return 判断页面返回的作品是否与爬取的目标作品匹配
     */
    public static boolean tvMatched(Map<String, Object> targetTvMap,
            String pageTvName, String pageTvType, List<String> pageActors,
            List<String> pageDirectors)
    {
        String tvName = targetTvMap.get("tvName") + StringUtils.EMPTY;
        String tvType = targetTvMap.get("tvType") + StringUtils.EMPTY;
        String alias = targetTvMap.get("alias") + StringUtils.EMPTY;
        String actors = targetTvMap.get("actor") + StringUtils.EMPTY;
        String directors = targetTvMap.get("director") + StringUtils.EMPTY;
        pageTvType = pageTvType == null ? StringUtils.EMPTY : pageTvType;
        pageTvName = pageTvName == null ? StringUtils.EMPTY : pageTvName;

        if(RegexUtils.regexMatch(RegexUtils.REGEX_CH,pageTvType))
            pageTvType=TVProcessUtils.getTVType(pageTvType);

        return pageTvType.contains(tvType)
                && tvNameMatched(pageTvName, tvName, alias) && tvActorsMatched(
                tvType, actors, directors, pageActors, pageDirectors);
    }

    /**
     * 作品按照名称、别名匹配
     *
     * @param pageTVName 页面中的作品名称
     * @param tvName     库中的作品名称
     * @param alias      别名中的作品名称
     * @return 是否匹配
     */
    private static boolean tvNameMatched(String pageTVName, String tvName,
            String alias)
    {
        if (pageTVName.equals(tvName))
            return true;
        List<String> aliasList = Arrays
                .asList(alias.split(SepratorUtil.SEP_COMMA_EN));
        if (aliasList.contains(pageTVName))
            return true;
        if (RegexUtils.regexMatch(tvName + "( {0,4})([^ ]+)版", pageTVName))
            return true;
        if (RegexUtils.regexMatch(
                tvName + "( {0,4})(\\[|\\(|（)([^ ]+)版(\\]|\\)|）)", pageTVName))
            return true;

        if (quarterMatched(aliasList, pageTVName))
            return true;

        return false;
    }

    /**
     * 季号匹配
     *
     * @param aliasList  别名列表
     * @param pageTVName 页面中的剧名
     * @return 匹配结果
     */
    private static boolean quarterMatched(List<String> aliasList,
            String pageTVName)
    {
        String regxVer = "(第([1-9][0-9]*)季|第([一-十]+)季)";
        String regxName = "(.+)" + regxVer + "$";
        if (!RegexUtils.regexMatch(regxName, pageTVName))
            return false;
        String mainName = RegexUtils
                .replaceStr(pageTVName, regxVer, StringUtils.EMPTY).trim();
        String version = RegexUtils.regexSearch(regxVer, pageTVName)
                .replaceAll("第|季", StringUtils.EMPTY);

        for (String alias : aliasList)
        {
            if (RegexUtils.regexMatch(regxName, alias))
            {
                String aliasName = RegexUtils
                        .replaceStr(alias, regxVer, StringUtils.EMPTY).trim();
                String aliasVers = RegexUtils.regexSearch(regxVer, alias)
                        .replaceAll("第|季", StringUtils.EMPTY);
                if (mainName.equals(aliasName) && (version.equals(aliasVers)
                        || StringUtil.chineseNumber2Int(version).equals(
                        StringUtil.chineseNumber2Int(aliasVers))))
                    return true;
            }
        }
        return false;
    }

    public static void main(String[] args)
    {
        System.out.println(tvNameMatched("花间提壶方大厨第三季", "花间提壶方大厨", ""));
    }

    /**
     * 电视剧、电影、网剧等影视作品按照主演、导演（不是必须）来匹配，其余作品类型不用这么严格
     *
     * @param tvType        目标作品类型
     * @param actors        目标作品主演
     * @param directors     目标作品导演
     * @param pageActors    页面中作品主演
     * @param pageDirectors 页面中作品导演
     * @return 是否匹配
     */
    private static boolean tvActorsMatched(String tvType, String actors,
            String directors, List<String> pageActors,
            List<String> pageDirectors)
    {
        if (!TV_MOV_TYPE_LIST.contains(tvType))
            return true;

        // 该目标作品没有主演和导演信息，无法进行判断
        if (StringUtils.isEmpty(actors) && StringUtils.isEmpty(directors))
            return true;

        boolean emptyPageActor = (pageActors == null || pageActors.isEmpty());
        boolean emptyPageDirector = (pageDirectors == null
                || pageDirectors.isEmpty());

        // 目标作品无主演信息，页面无导演信息，无法进行判断
        if (StringUtils.isEmpty(actors) && emptyPageDirector)
            return true;

        // 页面无主演信息，则匹配失败
        if (emptyPageActor)
            return false;

        return checkArrayStrContains(actors, pageActors)
                && ((emptyPageDirector || StringUtils.isEmpty(directors)) ? true
                : checkArrayStrContains(directors, pageDirectors));
    }

    /**
     * 获取页面中剧的名字
     *
     * @param tvMap 剧信息
     * @return 页面中剧名
     */
    public static String getPageTVName(Map<String, Object> tvMap)
    {
        if (tvMap == null)
            return null;
        if (tvMap.get(PAGE_TVNAME) == null
                || StringUtils.isEmpty(tvMap.get(PAGE_TVNAME).toString()))
            return (tvMap.get("tvName") + "");
        return tvMap.get(PAGE_TVNAME).toString();

        // return tvMap.get("tvName") + "";
    }

    /**
     * 获取页面中的剧更新集数
     *
     * @param tvMap 剧信息
     * @return 更新集数
     */
    public static String getPageUpdateSet(Map<String, Object> tvMap)
    {
        if (tvMap == null)
            return null;
        if (tvMap.get(PAGE_UPDATE_SET) == null
                || StringUtils.isEmpty(tvMap.get(PAGE_UPDATE_SET).toString()))
            return null;
        return tvMap.get(PAGE_UPDATE_SET).toString();
    }

    /**
     * 判断list中是否包含字符串中的2个以上的结果,当传入的结果为null时，默认为包含
     *
     * @param arrayStr A,B,C,D
     * @param list     [A,B,C,D]
     * @return
     */
    public static boolean checkArrayStrContains(String arrayStr,
            List<String> list)
    {

        if (StringUtil.isEmpty(arrayStr) || list == null || list.size() == 0)
            return false;
        String[] array = arrayStr.split(SepratorUtil.SEP_COMMA_EN);
        if (array.length == 0)
            return false;
        else if (array.length <= 3)
        {
            for (String item : array)
                if (list.contains(item))
                    return true;
        }
        else
        {
            int count = 0;
            for (String item : array)
            {
            	if (list.contains(item))
            		count++;
            	
                if (list.size() == count || count >= 1)
                    return true;

            }
        }
        return false;
    }

    /**
     * 作品类型中文名字转成tvtype
     *
     * @param typeName 作品类型中文名称
     * @return tvtype
     */
    public static String getTVType(String typeName)
    {
        String del = "xxx";
        if (StringUtils.isEmpty(typeName))
            return del;
        String tvType;
        switch (typeName)
        {
            case "电视剧":
            case "网络剧":
                tvType = "1,3";
                break;
            case "电影":
            case "微电影":
            case "网络大电影":
                tvType = "2,4,6";
                break;
            case "栏目":
            case "综艺":
                tvType = "5";
                break;
            default:
                tvType = del;
                break;
        }
        return tvType;
    }

    public static void addTVFromSearchList(Page page,
            Map<String, Object> tvinfoMap, List<String> names,
            List<String> links, List<String> tvTypes,
            List<List<String>> pageActors, List<List<String>> pageDirector,
            TVProcessUtils.TVMatcher matcher,
            TVProcessUtils.UpdateSetGetter getter)
    {
        if (LOGGER.isDebugEnabled())
        {
            LOGGER.debug("tvInfo:" + GsonUtils.toJson(tvinfoMap));
            LOGGER.debug("names:" + GsonUtils.toJson(names));
            LOGGER.debug("links:" + GsonUtils.toJson(links));
            LOGGER.debug("tvTypes:" + GsonUtils.toJson(tvTypes));
            // LOGGER.debug("releasetimes:" + GsonUtils.toJson(releasetimes));
        }

        if (matcher == null)
            matcher = new TVProcessUtils.TVMatcher();

        boolean noData = true;
        for (int i = 0; i < names.size(); i++)
        {
            List<String> director;
            if (null == pageDirector)
            {
                director = null;
            }
            else
            {
                director = pageDirector.get(i);
            }
            List<String> actor;
            if (null == pageActors)
            {
                actor = null;
            }
            else
            {
                actor = pageActors.get(i);
            }

            tvinfoMap.put(PAGE_TVNAME, names.get(i));
            if (getter != null)
            {
                String updateSet = getter.getUpdateSet(i);
                if (StringUtils.isNotEmpty(updateSet))
                    tvinfoMap.put(PAGE_UPDATE_SET, updateSet);
            }

            if (matcher.addTV(page, tvinfoMap, names.get(i), tvTypes.get(i),
                    actor, director, links.get(i), i))
            {
                noData = false;
                // break;
            }
        }
        if (noData)
        {
            LOGGER.warn("html:{}", page.getHtml() == null ? "empty!"
                    : page.getHtml().toString());
            throw new SpiderException(SpiderExceptionCode.DataInvalideException,
                    "NO TV Matched:" + tvinfoMap.get("tvName"));
        }
    }

    /**
     * 作品匹配器
     *
     * @类名 TVMatcher
     * @日期 2017年4月12日
     * @作者 高海军
     * @功能 根据条件判断爬取到的作品是否为目标作品
     */
    public static class TVMatcher
    {
        protected boolean addTV(Page page, Map<String, Object> tvinfoMap,
                String name, String tvType, List<String> pageActors,
                List<String> pageDirector, String link, int idx)
        {
            if (TVProcessUtils.tvMatched(tvinfoMap, name,
                    TVProcessUtils.getTVType(tvType), pageActors, pageDirector))
            {
                if (StringUtils.isNotEmpty(link))
                    PageUtils.addTargetRequest(page, link, tvinfoMap, true);
                return true;
            }
            return false;
        }
    }

    /**
     * 更新集数获取器
     *
     * @类名 UpdateSetGetter
     * @日期 2017年4月12日
     * @作者 高海军
     * @功能 获取目标作品的更新集数
     */
    public static abstract class UpdateSetGetter
    {
        public abstract String getUpdateSet(int idx);
    }

    public static String getTVTypeName(String typeId)
    {
        if (StringUtils.isEmpty(typeId))
            return StringUtils.EMPTY;
        String tvType;
        switch (typeId)
        {
            case "1":
                tvType = "电视剧";
                break;
            case "3":
                tvType = "网剧";
                break;
            case "2":
            case "4":
            case "6":
                tvType = "电影";
                break;
            default:
                tvType = "综艺";
                break;
        }
        return tvType;
    }

    public static String getTVKeyWord(JSONObject target)
    {
        if (target == null || !target.has("tvName"))
            return StringUtils.EMPTY;
        String keyWord = target.getString("tvName");
        String tvType = target.has("tvType")
                ? " " + getTVTypeName(target.getString("tvType"))
                : StringUtils.EMPTY;
        return KeywordEncode.encode(keyWord + tvType);

    }
}